#!/usr/bin/python3
import cv2 as cv
import os
import numpy as np
import paho.mqtt.client as mqtt
import hashlib
import time
import socket
import json
# MQTT服务器地址和端口号
mqtt_broker = "43.136.77.177"
mqtt_port = 1883

# 创建MQTT客户端实例
client = mqtt.Client()
client.connect(mqtt_broker, mqtt_port, 60)

#建立tcp
HOST = '0.0.0.0'
PORT = 5252
# 创建socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定主机和端口
s.bind((HOST, PORT))
# 监听连接
s.listen(1)
print('等待连接...')
# 接受连接
client_socket, client_address = s.accept()
print('已连接：', client_address)
# 创建名为face的文件夹，用于保存人脸数据
if not os.path.exists('face'):
    os.mkdir('face')

# 创建空字典用于保存人脸哈希值数据
face_hashes = {}
face_folder = 'face'
for file_name in os.listdir(face_folder):
    if file_name.endswith('.png'):
        face_hash = file_name[:-4]
        face = cv.imread(os.path.join(face_folder, file_name), cv.IMREAD_GRAYSCALE)
        face_hashes[face_hash] = face
#建立esp32连接
c_t = time.time()
# 在每一帧数据中进行人脸识别
while HOST:  # 摄像头开启后执行
    if HOST:
        # 接收图像数据长度
        data_len = client_socket.recv(16)
        data_len = int(data_len.decode().strip())
        print('接收数据理论长度:', data_len)

        # 循环接收图像数据
        buf = b''
        while len(buf) < data_len:
            data = client_socket.recv(data_len - len(buf))
            if not data:
                break
            buf += data

        print('接收完成! 图像数据长度:', len(buf))

        # 将图像数据转换为numpy数组
        np_data = np.frombuffer(buf, dtype=np.uint8)

        # 解码图像数组
        frame = cv.imdecode(np_data, cv.COLOR_RGB2BGR)
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  # 以灰度图的形式读取图像

        # 实例化OpenCV人脸识别的分类器
        face_cascade = cv.CascadeClassifier(r'haarcascade_frontalface_default.xml')
        face_cascade.load(r'haarcascade_frontalface_default.xml')

        # 调用识别人脸
        faceRects = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))

        # 保存人脸哈希值数据
        if cv.waitKey(1) & 0xFF == ord('1'):
            for faceRect in faceRects:
                x, y, w, h = faceRect
                face = gray[y:y + h, x:x + w]
                face = np.ascontiguousarray(face)
                face_hash = hashlib.md5(face).hexdigest()
                face_hashes[face_hash] = face
                cv.imwrite(f"face/{face_hash}.png", face)
                print(f"Saved face with hash: {face_hash}")

        # 检查是否匹配已保存的人脸数据，并发送MQTT消息
        for faceRect in faceRects:
            x, y, w, h = faceRect
            face = gray[y:y + h, x:x + w]
            for face_hash, saved_face in face_hashes.items():
                result = cv.matchTemplate(saved_face, face, cv.TM_CCOEFF_NORMED)
                l_t=time.time()
                if result.max() > 0.8:
                    l_t = time.time()
                    if l_t - c_t > 1:
                        message = {"door": 1}  # 创建包含"door"键和值1的字典
                        json_message = json.dumps(message)  # 将字典转换为JSON字符串
                        client.publish("system/sub", json_message)  # 发布JSON字符串到主题"system/sub"
                        print("on!")
                        c_t = time.time()

                l2_t = time.time()
                if l2_t - c_t > 4:
                    message = {"door": 0}  # 创建包含"door"键和值0的字典
                    json_message = json.dumps(message)  # 将字典转换为JSON字符串
                    client.publish("system/sub", json_message)  # 发布JSON字符串到主题"system/sub"
                    print("off!")
                    c_t = time.time()
                    break


        # 显示人脸框
        for faceRect in faceRects:
            x, y, w, h = faceRect
            cv.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
        #cv.imshow("frame", frame)

    if cv.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
cv.destroyAllWindows()